/**
 * \file Dictionnaire.h
 * \brief Ce fichier contient l'interface d'un dictionnaire.
 * \author Admin
 * \version 0.1
 * \date juin 2014
 * 
 */


#ifndef DICO_H_
#define DICO_H_

#include <stdexcept>
#include <iostream>
#include <fstream> // pour les fichiers
#include <string>
#include <vector>

namespace TP2P1
{
/**
* \class Dictionnaire
*
* \brief classe représentant un dictionnaire
*
*  La classe gère un pointeur sur la racine du dictionnaire
*/
class Dictionnaire
{
public:

	/*
	*\brief		Constructeur 
	*
	*\post		Une instance vide de la classe a été initialisée
	*
	*/
	Dictionnaire();

	/*
	*\brief		Constructeur de dictionnaire à partir d'un fichier
	*
	*\pre		Il y a suffisament de mémoire
	*\pre		Le fichier est ouvert au préalable
	*
	*\post		Si le fichier est ouvert, l'instance de la classe a été initialisée à partir du fichier de dictionnaire. Sinon, on génère une classe vide.
	*
	*\exception	bad_alloc s'il n'y a pas assez de mémoire
	*
	*/
	Dictionnaire(std::ifstream &fichier);


	/*
	*\brief		Destructeur
	*
	*\post		Une instance de la classe est détruite
	*
	*/
	~Dictionnaire();

	/*
	*\brief		Ajouter un mot au dictionnaire et l'une de ses traductions en équilibrant l'arbre AVL
	*			
	*\pre		Il y a suffisament de mémoire
	*
	*\post		Le mot est ajouté au dictionnaire
	*
	*\exception	bad_alloc si il n'y a pas suffisament de mémoire
	*
	*/
	void ajouteMot(const std ::string& motOriginal, const std ::string& motTraduit);

	/*
	*\brief		Supprimer un mot et équilibrer l'arbre AVL
	*
	*\pre		L'arbre n'est pas vide
	*\pre		Le mot à enlever appartient au dictionnaire
	*
	*\post		Si le mot appartient au dictionnaire, on l'enlève et on équilibre. Sinon, on ne fait rien.
	*
	*\exception	logic_error si l'arbre est vide
	*\exception	logic_error si le mot n'appartient pas au dictionnaire
	*/
	void supprimeMot(const std ::string& motOriginal);

	/*
	*\brief		Quantifier la similitude entre 2 mots (dans le dictionnaire ou pas)
	*			Ici, 1 représente le fait que les 2 mots sont identiques, 0 représente le fait que les 2 mots sont complètements différents
	*
	*\post		Le dictionnaire est inchangée.
	*\post		On retourne une valeur entre 0 et 1 quantifiant la similarité entre les 2 mots donnés
	*
	*/
	double similitude(const std ::string& mot1, const std ::string& mot2);


	/*
	*\brief		Suggère des corrections pour le mot motMalEcrit sous forme d'une liste de mots, dans un vector, à partir du dictionnaire
	*
	*\pre		Le dictionnaire n'est pas vide
	*
	*\post		S'il y a suffisament de mots, on redonne 10 corrections possibles au mot donné. Sinon, on en donne le plus possible
	*
	*\exception	logic_error si le dictionnaire est vide
	*/
	std::vector<std::string> suggereCorrections(const std ::string& motMalEcrit);

	/*
	*\brief		Trouver les traductions possibles d'un mot
	*
	*\post		Si le mot appartient au dictionnaire, on retoune la liste des traductions du mot donné.
	*\post		Sinon, on retourne un vecteur vide
	*\post		Le dictionnaire reste inchangée
	*
	*/
	std::vector<std::string> traduit(const std ::string& mot);

	/*
	*\brief		Vérifier si le mot donné appartient au dictionnaire
	*
	*\post		Le dictionnaire reste inchangé
	*\post		On retourne true si le mot est dans le dictionnaire. Sinon, on retourne false.
	*
	*/
	bool appartient(const std::string &data);

	/*
	*\brief		Vérifier si le dictionnaire est vide
	*
	*\post		Le dictionnaire est inchangé
	*
	*/
	bool estVide() const;

	/**
	 * \brief méthode pour afficher les mots du dictionnaire en ordre alphabétique en console
	 *
	 * \post le dictionnaire est inchangé
	 */
	void afficherSymetrique() const;

	/**
	 * \brief renvoie le nombre de mots dans le dictionnaire
	 */
	int nombreDeMot() const;

private:

	class NoeudDictionnaire
	{
	public:

		std::string mot;						// Un mot (en anglais)

		std::vector<std::string> traductions;	// Les diff�rentes traductions possibles en fran�ais du mot en anglais
												// Par exemple, la liste fran�aise { "contempler", "envisager" et "pr�voir" }
												// pourrait servir de traduction du mot anglais "contemplate".

	    NoeudDictionnaire *gauche, *droite;		// Les enfants du noeud

	    int hauteur;							// La hauteur de ce noeud (afin de maintenir l'�quilibre de l'arbre AVL)

		// Vous pouvez ajouter ici un contructeur de NoeudDictionnaire
	    NoeudDictionnaire(const std::string& s):mot(s), traductions(), gauche(NULL), droite(NULL), hauteur(0)
	    {}
	};

   typedef NoeudDictionnaire * elem;

   elem racine;			// La racine de l'arbre des mots

   int cpt;				// Le nombre de mots dans le dictionnaire

   //Vous pouvez ajouter autant de méthodes privées que vous voulez

   /**
    * \brief méthode auxiliaire à la méthode ajouteMot. Permet d'insérer un mot dans l'arbre.
    *
    *\pre Il y a suffisament de mémoire
	*
	*\post Le mot est ajouté au dictionnaire
	*
	*\exception	bad_alloc si il n'y a pas suffisament de mémoire
    */
   void _auxAjouteMot(elem&, const std::string&, const std::string&);

   /**
    * \brief méthode auxiliaire à la méthode supprimeMot. Permet de retirer un mot du dictionnaire.
    *
    * \pre le mot est présent dans le dictionnaire
    * \post le mot n'est plus dans le dictionnaire
    *
    * \exception logic_error si le mot n'est pas dans le dictionnaire
    */
   bool _auxSupprimeMot(elem&, const std::string&);

   /**
    * \brief méthode utilitaire pour avoir la hauteur d'un noeud
    */
   int _hauteur(elem&);

   /**
    * \brief méthode utilitaire pour balancer l'arbre
    *
    * \post l'arbre dont la racine est le noeud passé en argument est balancé.
    */
   void _balancer(elem&);

   /**
    * \brief méthode pour faire une rotation gauche à partir du noeud donné en argument
    */
   void _zigZigGauche(elem&);

   /**
    * \brief méthode pour faire une rotation droite à partir du noeud donné en argument
    */
   void _zigZigDroit(elem&);

   /**
    * \brief méthode pour faire une rotation droite sur le noeud gauche du noeud passé en argument
    * 	et ensuite une rotation gauche à partir de ce noeud.
    */
   void _zigZagGauche(elem&);

   /**
    * \brief méthode pour faire une rotation gauche sur le noeud droit du noeud passé en argument
    * 	et ensuite une rotation droite à partir de ce noeud.
    */
   void _zigZagDroit(elem&);

   /**
    * \brief méthode pour afficher les mots du dictionnaire en ordre symétrique
    * \post le dictionnaire est inchangé
    */
   void _auxAfficherSymetrique(elem) const;

   /**
    * \brief permet de récupérer le noeud minimum du sous-arbre dont la racine est le noeud passé en argument.
    */
   elem& _noeudMinimum(elem&);

   /**
    * \brief permet de supprimer le noeud minimum du sous-arbre dont la racine est le noeud passé en argument.
    */
   void _retireMinimum(elem&);

   /**
    * \brief méthode permettant d'ajuster la hauteur de tous les noeuds de l'arbre dont la racine est le noeud passé en argument.
    */
   int _ajusterHauteur(elem&);

   /**
    * \brief méthode auxiliaire à la méthode appartient, permet de savoir si un mot est dans le dictionnaire
    */
   bool _auxAppartient(elem&, const std::string&) const;

   /**
    * \brief permet de proprement libérer la mémoire pour tous les noeuds de l'arbre
    */
   void _detruire(elem&);


   /*
   	*\brief		méthode auxiliaire à suggereCorrections pour trouver des corrections pour un mot mal écrit
   	*/
   	void _auxSuggereCorrections(elem courant, std::vector< std::pair < std::string,double > > & suggestions, const std ::string& motMalEcrit,
   			double& minCourantSuggestions);


   	/**
	 *  \brief méthode qui ajoute une suggestion au vecteur auxSuggestion
	 */
   	void _auxAjoutSuggestion(std::vector< std::pair < std::string,double > > & suggestions, std::string motAAjouter, double similarite,
   			double& minCourantSuggestions);

   	/**
	 *  \brief courte description de la méthode
	 *  \pre precondition
	 *  \post postcondition
	 *  \exception
	 */
   	std::vector<std::string> _preparerSuggestions(std::vector< std::pair < std::string,double > > & auxSuggestions);

   	/**
	 *  \brief méthode auxiliaire récursive pour trouver la traduction d'un mot.
	 */
   	void _auxTraduit(elem courant, const std::string& mot, std::vector<std::string>& traduction);


};

bool charSpecial(char);

}

#endif /* DICO_H_ */
